package httpHandler

import (
	"fmt"
	baseHttp "gitee.com/zaiqiang231/go-base-app/base_app/http"
	"gitee.com/zaiqiang231/zcamp-service-user/app/config"
	"github.com/gin-gonic/gin"
	"github.com/mojocn/base64Captcha"
	"github.com/songzhibin97/gkit/cache/local_cache"
	"net/http"
	"sync"
	"time"
)

var (
	captchaCache     *local_cache.Cache
	onceCaptchaCache sync.Once
	CaptchaStore     = base64Captcha.DefaultMemStore
)

func GetCaptchaCache() (*local_cache.Cache, error) {
	onceCaptchaCache.Do(func() {
		tmp := local_cache.NewCache(
			local_cache.SetDefaultExpire(config.GlobalAppConfig.CaptchaConfig.OpenCaptchaTimeOut),
		)
		captchaCache = &tmp
	})

	if captchaCache == nil {
		return nil, fmt.Errorf("GetCaptchaCache nil")
	}

	return captchaCache, nil
}

func Captcha(c *gin.Context) {
	// 判断验证码是否开启
	openCaptcha := config.GlobalAppConfig.CaptchaConfig.OpenCaptcha               // 是否开启防爆次数
	openCaptchaTimeOut := config.GlobalAppConfig.CaptchaConfig.OpenCaptchaTimeOut // 缓存超时时间

	key := c.ClientIP()
	cache, err := GetCaptchaCache()
	if err != nil {
		baseHttp.WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	v, ok := cache.Get(key)
	if !ok {
		cache.Set(key, 1, time.Second*time.Duration(openCaptchaTimeOut))
	}

	var oc bool
	if openCaptcha == 0 || openCaptcha < interfaceToInt(v) {
		oc = true
	}

	// 字符,公式,验证码配置
	// 生成默认数字的driver
	driver := base64Captcha.NewDriverDigit(
		config.GlobalAppConfig.CaptchaConfig.ImgHeight,
		config.GlobalAppConfig.CaptchaConfig.ImgWidth,
		config.GlobalAppConfig.CaptchaConfig.KeyLong, 0.7, 80)
	// cp := base64Captcha.NewCaptcha(driver, store.UseWithCtx(c))   // v8下使用redis
	cp := base64Captcha.NewCaptcha(driver, CaptchaStore)
	id, b64s, err := cp.Generate()

	if err != nil {
		baseHttp.WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}
	baseHttp.WriteResponse(c, 0, "success", SysCaptchaResponse{
		CaptchaId:     id,
		PicPath:       b64s,
		CaptchaLength: config.GlobalAppConfig.CaptchaConfig.KeyLong,
		OpenCaptcha:   oc,
	})
}

// 类型转换
func interfaceToInt(v interface{}) (i int) {
	switch v := v.(type) {
	case int:
		i = v
	default:
		i = 0
	}
	return
}

type SysCaptchaResponse struct {
	CaptchaId     string `json:"captchaId"`
	PicPath       string `json:"picPath"`
	CaptchaLength int    `json:"captchaLength"`
	OpenCaptcha   bool   `json:"openCaptcha"`
}

type CaptchaCheckReq struct {
	Captcha   string `json:"captcha" validate:"required"`   // 验证码
	CaptchaId string `json:"captchaId" validate:"required"` // 验证码ID
}
